package com.study.thread.unsafeAndCas;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

/*
 *  CAS: 是比较交换，将修改前的值和变量值进行比较如果比较对了就修改新值，失败则可以重试
 *      优点：可以避免使用锁从而导致因为争抢锁带来的上下文切换和重新调度线程的开销。
 *      缺点：当很多线程都对一个变量进行操作，这会造成一直循环造成cpu开销过大
 *      ABA问题：当线程1首先获得到变量C的值为A，线程2此时也获取到了变量C的值为A,线程2通过CAS操作将变量C的值从A变成了B，然后又从B变成了A，
 *              此时线程1在去替换A换成B，但是线程1获取的值已经不是原来的A了，就导致了ABA问题，提供了AtomicStampedReference来解决这个问题。
 *  Unsafe：是java提供了一系列CAS操作的原子性工具类，其方法都是native修饰的，方法都是通过JNI的方式调用本地C++实现库，
 *          其原子类都是通过Unsafe提供的方法来实现原子操作的
 *          compareAndSwapInt(Object var1, long var2, int var4, int var5)：用来比较交换，将旧值，替换成新值
 *                 第一个参数是修改的参数对象是哪个(可以看成内存地址)，
 *                 第二个是对象里修改的变量的偏移量，应该是确认在对象里的位置
 *                 第三个是变量的当前值(修改前的值)，这时底层会拿到偏移量的值，和当前值进行比较，比较对了修改为第四个传入的值（新值）
 *                 第四个是新值
 *             总结：当比较交换时，如果成功则返回true/失败false，cas操作会
 *          getIntVolatile(Object var1, long var2)：获取当前的值
 *                 第一个参数是修改的参数对象是哪个(可以看成内存地址)，
 *                 第二个是对象里修改的变量的偏移量，应该是确认在对象里的位置
 *          getAndAddInt(Object var1, long var2, int var4)：获取修改前旧值，并修改新值
 *                 第一个参数是修改的参数对象是哪个(可以看成内存地址)，
 *                 第二个参数是对象里修改的变量的偏移量，应该是确认在对象里的位置
 *                 第三个参数是新值
 *             总结：底层也是采用的compareAndSwapInt，第三个参数当前值(修改前的值)，是通过getIntVolatile获取到的，然后通过do-while来cas重试修改
 *          objectFieldOffset(Field field)：获取变量的偏移量
 */

public class UnsafeDemo1 {

    private static Unsafe unsafe = null;
    private volatile int value;
    private static UnsafeDemo1 u1 = new UnsafeDemo1();
    private static long valueOffset;

    static {
        try {
            Class<?> aClass = Class.forName("java.util.concurrent.atomic.AtomicInteger");
            Object o = aClass.newInstance();
            Field unsafe1 = aClass.getDeclaredField("unsafe");
            unsafe1.setAccessible(true);
            unsafe = (Unsafe) unsafe1.get(o);
            valueOffset = unsafe.objectFieldOffset(UnsafeDemo1.class.getDeclaredField("value")); //获取偏移量
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {

        for (int i = 0; i < 50; i++) {
            new Thread(() -> {
                System.out.println(u1.increaseValue());
            }).start();
        }

        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                System.out.println(u1.decrease(1));
            }).start();
        }

        Thread.sleep(2000);
        System.out.println("ffffff：" + u1.get());
    }

    public int get() {
        return value;
    }

    public int increaseValue() {
//        do {
//
//        } while (!unsafe.compareAndSwapInt(this, valueOffset, this.value, this.value+1));
//
//        return this.value;
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

    public int increaseValue(int value) {
        return unsafe.getAndAddInt(this, valueOffset, value);
    }

    public int decrease(int value) {
        while (unsafe.compareAndSwapInt(this, valueOffset, this.value, this.value - value))
            return this.value;
        return 0;
    }


}
